//
// Created by LiuYou on 2021/8/18.
//

#define _GNU_SOURCE 1

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cassert>
#include <unistd.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <libgen.h>
#include <string>


static const int BUF_SIZE = 1024;


int main(int argc, char** argv) {
    if (argc < 3) {
        std::fprintf( stderr, "用法: %s ip port\n", basename( argv[0] ));
        exit( 1 );
    }
    const char* const ip = argv[1];
    int port = std::atoi( argv[2] );

    struct sockaddr_in serverSockAddrIn{
            .sin_family=PF_INET,
            .sin_port=htons( port ),
            {.s_addr=0}
    };
    inet_pton( AF_INET, ip, &serverSockAddrIn.sin_addr );

    int sockFD = socket( PF_INET, SOCK_STREAM, 0 );
    assert( sockFD >= 0 );

    if (connect( sockFD, (sockaddr*) &serverSockAddrIn, sizeof( serverSockAddrIn )) < 0) {
        std::perror( "connect()" );
        close( sockFD );
        exit( 1 );
    }


    // 监听标准输入和sockFD上发生的可读、可写和异常等事件。
    pollfd pollFDS[2]{
            {.fd=0,
                    // 监听 0 是否有数据可读。
                    .events=POLLIN, .revents=0},
            {.fd=sockFD,
                    // 监听 sockFD 是否有数据可读或者tcp连接是否被server关闭
                    .events=POLLIN | POLLRDHUP, .revents=0}
    };

    char readBuf[BUF_SIZE]{};
    int pipeFD[2];
    int ret = pipe( pipeFD );
    assert( ret != -1 );

    for (;;) {
        ret = poll( pollFDS, sizeof( pollFDS ), -1 );
        if (ret < 0) {
            std::fprintf( stderr, "poll()调用失败\n" );
            break;
        }

        if (pollFDS[1].revents & POLLRDHUP) {
            std::fprintf( stderr, "服务端关闭了连接\n" );
            break;
        } else if (pollFDS[1].revents & POLLIN) {
            std::memset( readBuf, '\0', sizeof( readBuf ));
            recv( pollFDS[1].fd, readBuf, sizeof( readBuf ) - 1, 0 );
            // 接受的数据:
            std::fprintf( stdout, "%s\n", readBuf );
        }

        if (pollFDS[0].revents & POLLIN) {
            splice( pollFDS[0].fd, NULL, pipeFD[1],
                    NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
            // 将从 0 输入的数据移动到 sockFD。
            splice( pipeFD[0], NULL, pollFDS[1].fd,
                    NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );

        }

    }

    close( sockFD );
    return 0;
}